/*
 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef DBCSTORE_H
#define DBCSTORE_H

#include "DBCFileLoader.h"

template<class T>
class DBCStorage
{
        typedef std::list<char*> StringPoolList;
    public:
        explicit DBCStorage(const char* f) : fmt(f), nCount(0), fieldCount(0), indexTable(NULL), m_dataTable(NULL), loaded(false)
        {
            data.clear();
        }
        ~DBCStorage()
        {
            Clear();
        }

        T const* LookupEntry(uint32 id) const
        {
            if (loaded)
            {
                typename std::map<uint32, T const*>::const_iterator it = data.find(id);
                if (it != data.end())
                    return it->second;
            }
            return (id >= nCount) ? NULL : indexTable[id];
        }
        uint32  GetNumRows() const
        {
            return loaded ? data.size() : nCount;
        }
        char const* GetFormat() const
        {
            return fmt;
        }
        uint32 GetFieldCount() const
        {
            return fieldCount;
        }

        bool Load(char const* fn)
        {
            DBCFileLoader dbc;
            // Check if load was sucessful, only then continue
            if (!dbc.Load(fn, fmt))
                return false;

            fieldCount = dbc.GetCols();
            m_dataTable = (T*)dbc.AutoProduceData(fmt, nCount, (char**&)indexTable);

            m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt, (char*)m_dataTable));

            // error in dbc file at loading if NULL
            return indexTable != NULL;
        }

        void SetEntry(uint32 id, T* t) // Cryptic they say..
        {
            if (!loaded)
            {
                for (uint32 i = 0; i < nCount; ++i)
                {
                    T const* node = LookupEntry(i);
                    if (!node)
                        continue;
                    data[i] = node;
                }
                loaded = true;
            }
            data[id] = t;
        }

        bool LoadStringsFrom(char const* fn)
        {
            // DBC must be already loaded using Load
            if (!indexTable)
                return false;

            DBCFileLoader dbc;
            // Check if load was successful, only then continue
            if (!dbc.Load(fn, fmt))
                return false;

            m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt, (char*)m_dataTable));

            return true;
        }

        void Clear()
        {
            if (loaded)
            {
                data.clear();
                loaded = false;
            }

            if (!indexTable)
                return;

            delete[] ((char*)indexTable);
            indexTable = NULL;
            delete[] ((char*)m_dataTable);
            m_dataTable = NULL;

            while (!m_stringPoolList.empty())
            {
                delete[] m_stringPoolList.front();
                m_stringPoolList.pop_front();
            }
            nCount = 0;
        }

    private:
        char const* fmt;
        uint32 nCount;
        uint32 fieldCount;
        T** indexTable;
        T* m_dataTable;
        std::map<uint32, T const*> data;
        bool loaded;
        StringPoolList m_stringPoolList;
};

#endif
